# Class to make requests through Bing Search API

=begin
Copyright (C) 2014 Enrique Rando

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

http://www.gnu.org/licenses/gpl-2.0.html
=end


require File.expand_path(File.dirname(__FILE__) + '/../Search_engine.rb')
require File.expand_path(File.dirname(__FILE__) + '/../My_HTTP_client.rb')

require 'uri'
require 'base64'
require 'rexml/document'

class Bing_api < Search_engine
	# Object creation
	#	Parameters
	#		key				Bing API APP key
	#		user_agent		User agent to use in requests
	#		max_requests	Maximum number of requests to make
	#		proxy			Proxy name or address. Use nil for no proxy.
	#						By default (:ENV), Ruby 2.1 uses HTTP_PROXY environment variable to set the proxy
	#		proxy_port		Proxy port
	#		proxy_user		Proxy username, if required
	#		proxy_password	Proxy password, if required.
	def initialize(key, user_agent="B-API-RubyProg", max_requests=3, proxy=:ENV, proxy_port=nil, proxy_user=nil, proxy_password=nil)
		# API parameters
		@base_parameters = {
			'$top' => 50,
			'Adult'=>"'off'",
			'WebFileType'=>"'HTML'"
		}
		
		# Set instance info
		@user_agent = user_agent
		@protocol = :https
		@server = 'api.datamarket.azure.com'
		@port = :default
		@cookies = false
		@url = '/Bing/Search/v1/Web'
		@key = key
		@max_requests = max_requests
		@search_engine_bot = "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"

		# Establish connection
		connect_through(proxy, proxy_port, proxy_user, proxy_password)
	end
	
	# Makes a request to search engine
	# Parameters
	#	query		Query to make
	#	page		page number to request
	def request(query, page=1)
		# Prepare GET parameters
		parameters = @base_parameters.clone
		parameters['Query'] = "'#{query}'"
		parameters['$skip'] = (page - 1) * 50
		
		# Make the HTTPS request
		response = @client.get(@url, parameters, {})
		return nil if response.nil?

		# URL a user would use to make a search
		referer = "https://www.bing.com/search?q=#{URI.encode_www_form_component(query)}"
		return process(response, referer)
	end
	
	# Establish connection
	# Parameters
	#		proxy			Proxy name or address. Use nil for no proxy.
	#						By default (:ENV), Ruby 2.1 uses HTTP_PROXY environment variable to set the proxy
	#		proxy_port		Proxy port
	#		proxy_user		Proxy username, if required
	#		proxy_password	Proxy password, if required.	
	def connect_through(proxy=:ENV, proxy_port=nil, proxy_user=nil, proxy_password=nil)
		super(proxy, proxy_port, proxy_user, proxy_password)
		# Set up API authentication
		@client.change_auth(@key, @key)
	end
	
private

	# Process an API response to get data
	# Parameters
	#	response	The HTTP response
	#	referer		URL to use as referer when simulating SER clicks
	def process(response, referer)
		# Response has XML format
		xml = REXML::Document.new(response.body)
		
		# Create the array of result data
		output = []
		xml.elements.each("feed/entry") do |result|
			output << {
				:date => get_date(result),
				:referer => referer,
				:document_type => get_document_type(result),
				:title => get_title(result),
				:url => get_url(result),
				:summary => get_summary(result),
				:cache => get_cache(result),
				:translate => get_translate(result),
				:bot_user_agent => @search_engine_bot,
				:s_e_object => self
			}
		end
		
		return output
	end
	
	# Functions to get each data item from the result
	# Parameter result		The result XML element
	def get_date(result)
		return get_path(result, "updated")
	end
	
	def get_url(result)
		return get_path(result, "content/m:properties/d:Url")
	end

	def get_document_type(result)
		return nil
	end
	
	def get_title(result)
		return get_path(result, "content/m:properties/d:Title")
	end

	def get_summary(result)
		return get_path(result, "content/m:properties/d:Description")
	end

	def get_cache(result)
		return nil
	end

	def get_translate(result)
		return nil
	end
	
	# Gets an element text, given its path relative to result
	# Parameters
	#	result		The result element
	#	path		The relative path
	def get_path(result, path)
		tmp = result.elements[path]
		
		return tmp.nil? ? nil : tmp.text.force_encoding("ascii-8bit")
	end
end
